package com.ll19.thread.test.demo2ThreadLocal;

import java.util.Random;

/**
 * 加了个synchronized，不会出现竞争了，但是效率极低
 * 
 * 两个线程在accessStudent方法处串行操作，所以整个程序时间变长，大约10秒。消除了竞争
 * 
 * @author dachuan
 * 
 */
public class ThreadDemo2 implements Runnable {
	Student student = new Student();

	public static void main(String[] agrs) {
		ThreadDemo2 td = new ThreadDemo2(); 
		// ThreadDemo2 td = new ThreadDemo2();
		// ThreadDemo2 td2 = new ThreadDemo2();
		Thread t1 = new Thread(td, "a");
		Thread t2 = new Thread(td, "b");
		// 之所以t1,t2两个线程会在acessStudent函数处出现同步，是因为他们都是对同一个实例的函数进行访问
		// t1,t2都在对ThreadDemo2这个类的实例td的函数accessStudent进行访问，所以会出现同步。
		// 也就是说，如果类A内部定义了一个synchronized方法，而a是A的一个实例，如果有不同的线程都对a.syn()进行访问，就会出现同步
		// synchronized关键字是锁住了类的实例，让另外的线程进不去
		// 在这个例子中，t1,t2两个线程，总共运行时间肯定>=10秒，因为t1,t2在accessStudent这个地方是串行的。
		// 如果t1,t2是为了完成某件事情在合作，那么这个同步是值得的。
		// 现在的前提是，t1,t2必须使用同一个类的实例，但是又做的都是独立的事情。这个时候，synchronized方法显得很低效，反而降低了运算效率
		// 所以ThreadLocal的出现就是为了解决这个问题的。
		// ThreadLocal的应用场合：
		// 1.多个线程都要使用同一个类实例
		// 2.这多个线程拿到这个类实例后做的事情是互相独立的
		// 生产者和消费者模型跟ThreadLocal的应用场合有一个区别
		// 1.生产者和消费者两个线程其实也是在使用同一个类实例
		// 2.但是这两个线程拿到类实例后做的事情是互相牵制的
		t1.start();
		t2.start();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		accessStudent();
	}

	public synchronized void accessStudent() {
		String currentThreadName = Thread.currentThread().getName();
		System.out.println(currentThreadName + " is running!");
		// System.out.println("first read age is:"+this.student.getAge());
		Random random = new Random();
		int age = random.nextInt(100);
		System.out
				.println("thread " + currentThreadName + " set age to:" + age);
		this.student.setAge(age);
		System.out.println("thread " + currentThreadName
				+ " first read age is:" + this.student.getAge());
		try {
			Thread.sleep(5000);
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
		System.out.println("thread " + currentThreadName
				+ " second read age is:" + this.student.getAge());
	}
}
